home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / text / edit / NextStep14.lha / NextStep / source / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-18  |  38.3 KB  |  1,464 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  GoldED API client. ©1995 Dietmar Eilert. All Rights Reserved.
  4.  
  5.  Dice:
  6.  
  7.  dcc main.c cx.a sprintf.a -// -mRR -proto -2.0 -l tmsr.lib -l reqtoolssr.lib -o ram:dock
  8.  
  9.  Note: Compiling this code requires ToolManger includes & ToolManager linker
  10.        libraries. ToolManager is ©1990-1995 Stefan Becker.
  11.  
  12.   ------------------------------------------------------------------------------
  13. */
  14.  
  15. /// "includes"
  16.  
  17. #define Prototype extern
  18.  
  19. #include <exec/exec.h>
  20. #include <ctype.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <dos/dos.h>
  25. #include <dos/rdargs.h>
  26. #include <dos/dostags.h>
  27. #include <intuition/intuition.h>
  28. #include <workbench/startup.h>
  29. #include <rexx/errors.h>
  30. #include <rexx/rxslib.h>
  31. #include <rexx/storage.h>
  32. #include <libraries/reqtools.h>
  33. #include <utility/tagitem.h>
  34. #include <clib/toolmanager_protos.h>
  35. #include <clib/exec_protos.h>
  36. #include <clib/alib_protos.h>
  37. #include <clib/dos_protos.h>
  38. #include <clib/intuition_protos.h>
  39. #include <clib/utility_protos.h>
  40. #include <clib/rexxsyslib_protos.h>
  41. #include <clib/reqtools_protos.h>
  42. #include <clib/commodities_protos.h>
  43. #include "golded:api/include/golded.h"
  44.  
  45. #define SIG_KILL         SIGBREAKF_CTRL_C
  46. #define SIG_HANDSHAKE    SIGF_SINGLE
  47. #define TMET_Hotkey      10
  48. #define TMET_GoldED      11
  49.  
  50. ///
  51. /// "definitions"
  52.  
  53. // ToolManager objects are a combination of action/image/sound:
  54.  
  55. struct Tool {
  56.  
  57.     struct Node     Node;
  58.     APTR            Exec;
  59.     APTR            Icon;
  60.     APTR            Sound;
  61. };
  62.  
  63. // parser array: commands, templates, handlers
  64.  
  65. struct Parser { 
  66.  
  67.     UBYTE          *Command;
  68.     APTR            Server;
  69.     UBYTE          *Template;
  70. };
  71.  
  72. // linked list of all PROG objects (CLI/AREXX/HOTKEY/GOLDED) found in the preset file:
  73.  
  74. struct Event {
  75.  
  76.     struct Node     Node;
  77.     UWORD           Type;
  78.     UBYTE          *Command;
  79.     UBYTE          *Dir;
  80.     UBYTE          *Key;
  81.     UBYTE          *Output;
  82.     BOOL            Hotkey;
  83.     BOOL            Args;
  84.     BOOL            Activate;
  85. };
  86.  
  87. // linked list of all docks found in the preset file:
  88.  
  89. struct Dock {
  90.  
  91.     struct Node     Node;
  92.     struct TagItem *Tags;
  93.     BOOL            Visible;
  94.     UWORD           Elements;
  95. };
  96.  
  97. ///
  98. /// "prototypes"
  99.  
  100. Prototype void   InsertEvent(UBYTE *);
  101. Prototype void   PutIEvents(struct InputEvent *);
  102. Prototype int    main(int, char **);
  103. Prototype UBYTE *xsprintf(UBYTE *, UBYTE *);
  104. Prototype void   AddProg (ULONG *, struct List *);
  105. Prototype void   AddIcon (ULONG *, struct List *);
  106. Prototype void   AddSound(ULONG *, struct List *);
  107. Prototype void   AddTool (ULONG *, struct List *);
  108. Prototype void   AddDock (ULONG *, struct List *);
  109. Prototype void   HandleAPI(void);
  110. Prototype void   ReadConfig(UBYTE *);
  111. Prototype void   CloseRexxPort(struct MsgPort *, UWORD, BOOL);
  112. Prototype ULONG *SendRexxCommand(UBYTE *, UBYTE *, struct MsgPort *, BOOL, UWORD *, UBYTE *);
  113. Prototype struct Node *SearchName(struct List *, UBYTE *);
  114. Prototype void   FreeRexxCommand(struct RexxMsg *);
  115. Prototype UWORD  CountList(struct List *);
  116. Prototype void   Puts(UBYTE *);
  117. Prototype UBYTE *myprintf(UBYTE *, UBYTE *, ...);
  118. Prototype void   ARexxServer(void);
  119. Prototype void   ShowDocks(struct Dock *);
  120. Prototype void   HideDocks(void);
  121. Prototype void   DoExecute(UBYTE *, BOOL, UBYTE *, UBYTE *, UWORD, WORD);
  122. Prototype UBYTE *stristr(UBYTE *, UBYTE *);
  123. Prototype void   Replace(UBYTE *, UBYTE *, UBYTE *);
  124. Prototype void   CommandDispatch(struct RDArgs *, struct APIMessage *);
  125. Prototype LONG   ModifyDock(ULONG *, struct APIMessage *);
  126.  
  127. Prototype __stkargs struct InputEvent *MyInvertString(UBYTE *, APTR);
  128. Prototype __stkargs void               MyFreeIEvents(struct InputEvent *);
  129.  
  130. ///
  131. /// "globals"
  132.  
  133. UBYTE Version = "$VER: NeXTStep 1.4 (" __COMMODORE_DATE__ ")";
  134.  
  135. UWORD            ARexxReplies;
  136. struct Library  *ReqToolsBase;
  137. struct Library  *CxBase;
  138. struct Task     *MainTask;
  139. struct List      EventList, DockList;
  140. void            *TMHandle;
  141. UBYTE            Screen[255], Host[255];
  142.  
  143. // parser definitions used to scan preset file
  144.  
  145. struct Parser ConfigParser[] = {
  146.  
  147.     "PROG",  (APTR)AddProg,    "NAME/A,COMMAND/K/A,AREXX/S,CLI/S,HOTKEY/S,WB/S,DIR/K,OUTPUT/K,ARGS/S,KEY/K,GOLDED/S,ACTIVATE/S",
  148.     "SOUND", (APTR)AddSound,   "NAME/A,COMMAND/K/A,PORT/K/A",
  149.     "ICON",  (APTR)AddIcon,    "NAME/A,FILE/A",
  150.     "DTOOL", (APTR)AddTool,    "PROG/K/A,ICON/K,SOUND/K",
  151.     "DOCK",  (APTR)AddDock,    "NAME/A,X/N,Y/N,HORIZONTAL/S,COLUMNS/N,HOTKEY/K,TITLE/K,CENTER/S,POPUP/S,HIDDEN/S,TEXT/S,STICKY/S,FRONTMOST/S,PATTERN/S,VERTICAL/S,LINEAR/S",
  152.      NULL
  153. };
  154.  
  155. // parser definitions used to process commands sent by GoldED (API interface):
  156.  
  157. struct Parser CommandParser[] = {
  158.  
  159.     "DOCK",  (APTR)ModifyDock, "NAME/A,X/N,Y/N,SHOW/S,HIDE/S,TOGGLE/S,HORIZONTAL/S,VERTICAL/S,ROTATE/S,NEWLOOK/S,LINEAR/S",
  160.      NULL
  161. };
  162.  
  163. ///
  164. /// "main"
  165.  
  166. /* ----------------------------------- main ------------------------------------
  167.  
  168.  Start ToolManager, start background server (server performs all dock-related
  169.  actions, e.g. the server will run commands), read config file, call API loop.
  170.  
  171. */
  172.  
  173. int
  174. main(int argc, char **argv)
  175. {
  176.     if (FindPort("DOCKSERVER"))
  177.  
  178.         Puts("Can't run dock twice");
  179.  
  180.     else if (CxBase = OpenLibrary("commodities.library", 37)) {
  181.  
  182.         struct RDArgs *rdArgs;
  183.  
  184.         ULONG args[] = { 0, 0 };
  185.  
  186.         MainTask = FindTask(0);
  187.  
  188.         if (rdArgs = ReadArgs("CONFIG/K,HOST/K/A", args, NULL)) {
  189.  
  190.             UWORD  try;
  191.  
  192.             for (try = 20; !(TMHandle = AllocTMHandle()) && try; try--)
  193.                 Delay(10);
  194.  
  195.             if (TMHandle) {
  196.  
  197.                 struct Task *server;
  198.  
  199.                 if (server = (struct Task *)CreateNewProcTags(NP_Entry, ARexxServer, NP_Name, "DOCKSERVER", NP_Priority, 1, TAG_DONE)) {
  200.  
  201.                     NewList(&DockList );
  202.                     NewList(&EventList);
  203.  
  204.                     strcpy(Host, (UBYTE *)args[1]);
  205.  
  206.                     ReadConfig(args[0] ? (char *)args[0] : "progdir:dock.prefs");
  207.  
  208.                     if (DockList.lh_Head->ln_Succ)
  209.                         HandleAPI();
  210.  
  211.                     FreeTMHandle(TMHandle);
  212.  
  213.                     SetSignal(0, SIG_HANDSHAKE);
  214.  
  215.                     Signal(server, SIG_KILL);
  216.  
  217.                     Wait(SIG_HANDSHAKE);
  218.                 }
  219.             }
  220.             else
  221.                 Puts("got no ToolManager handle ?!");
  222.  
  223.             FreeArgs(rdArgs);
  224.         }
  225.         else
  226.             Puts("syntax error");
  227.  
  228.         CloseLibrary(CxBase);
  229.     }
  230.  
  231.     exit(0);
  232. }
  233.  
  234. /* ---------------------------------- wbmain -----------------------------------
  235.  
  236.  Workbench entry point; exit gracefully
  237.  
  238. */
  239.  
  240. int
  241. wbmain(struct WBStartup *startup)
  242. {
  243.     if (ReqToolsBase = OpenLibrary("reqtools.library", 37)) {
  244.  
  245.         rtEZRequestTags("No executable - to be used as GoldED API client", "OK", NULL, NULL, TAG_DONE);
  246.  
  247.         CloseLibrary(ReqToolsBase);
  248.     }
  249.  
  250.     exit(0);
  251. }
  252.  
  253.  
  254. ///
  255. /// "read config"
  256.  
  257. /* -------------------------------- ReadConfig ---------------------------------
  258.  
  259.  Read preset file. Build linked list of  dock  definitions  (DockList).  PROG
  260.  definitions  (AREXX/CLI/HOTKEY/GOLDED)  are  appended  to the EventList; the
  261.  contents of the EventList are examined if ToolManger tells us  that  a  dock
  262.  icon  has  been  activated  by the user. DTOOL definitions (command + icon +
  263.  sound) are appended to the <toolList>. The <tooList> is appended to the next
  264.  dock created by a DOCK line.
  265.  
  266. */
  267.  
  268. void
  269. ReadConfig(prefs)
  270.  
  271. UBYTE *prefs;
  272. {
  273.     BPTR config;
  274.  
  275.     if (config = Open(prefs, MODE_OLDFILE)) {
  276.  
  277.         struct RDArgs *rdArgs;
  278.  
  279.         struct List toolList;
  280.  
  281.         NewList(&toolList);
  282.  
  283.         if (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) {
  284.  
  285.             static UBYTE buffer[256];
  286.  
  287.             while (FGets(config, buffer, 255)) {
  288.  
  289.                 UBYTE *cmd;
  290.  
  291.                 for (strcat(buffer, "\12"), cmd = buffer; *cmd && (*cmd != ';'); ++cmd) {
  292.  
  293.                     if ((*cmd != ' ') && (*cmd != 10)) {
  294.  
  295.                         ULONG n, argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  296.  
  297.                         struct RDArgs *args;
  298.  
  299.                         for (n = 0; ConfigParser[n].Command; ++n) {
  300.  
  301.                             if (!memcmp(cmd, ConfigParser[n].Command, strlen(ConfigParser[n].Command))) {
  302.  
  303.                                 cmd += strlen(ConfigParser[n].Command);
  304.  
  305.                                 rdArgs->RDA_Source.CS_Buffer = cmd;
  306.                                 rdArgs->RDA_Source.CS_Length = strlen(cmd);
  307.                                 rdArgs->RDA_Source.CS_CurChr = 0;
  308.                                 rdArgs->RDA_DAList           = NULL;
  309.                                 rdArgs->RDA_Buffer           = NULL;
  310.  
  311.                                 if (args = ReadArgs(ConfigParser[n].Template, argArray, rdArgs)) {
  312.  
  313.                                     (*((void (*)(ULONG *, struct List *))ConfigParser[n].Server))(argArray, &toolList);
  314.  
  315.                                     FreeArgs(args);
  316.                                 }
  317.                                 else {
  318.  
  319.                                     PrintFault(IoErr(), "syntax error");
  320.                                     Puts(buffer);
  321.                                 }
  322.                             }
  323.                         }
  324.  
  325.                         break;
  326.                     }
  327.                 }
  328.             }
  329.  
  330.             FreeDosObject(DOS_RDARGS, rdArgs);
  331.         }
  332.  
  333.         Close(config);
  334.     }
  335.     else
  336.         Puts("dock preset file missing");
  337. }
  338.  
  339. /* ---------------------------------- AddProg ----------------------------------
  340.  
  341.  Add a command object (exec/WB/ARexx). The command definition is added to our
  342.  internal  EventList  only.  An  ARexx  object is added to ToolManagers pool,
  343.  telling ToolManager to send us the object's name upon activation: Events are
  344.  going  to be performed by us (i.e. the background task), not by ToolManager.
  345.  This gives us the opportunity to change  command  strings  before  execution
  346.  (e.g.  insert  GoldED's current screen name). Event definitions are added to
  347.  the <EventList>; we are going to scan this list if we recieve ARexx messages
  348.  by ToolManager to determine approbiate action.
  349.  
  350.  template: NAME/A,COMMAND/K/A,AREXX/S,CLI/S,HOTKEY/S,WB/S,DIR/K,OUTPUT/K,ARGS/S,KEY/K,GOLDED/S,ACTIVATE/S,SHANGHAI/N",
  351.  
  352. */
  353.  
  354. void
  355. AddProg(args, toolList)
  356.  
  357. ULONG       *args;
  358. struct List *toolList;
  359. {
  360.     struct Event *event;
  361.  
  362.     if (event = malloc(sizeof(struct Event))) {
  363.  
  364.         UBYTE *name = strdup((UBYTE *)args[0]);
  365.  
  366.         struct TagItem execTags[] = {
  367.  
  368.             TMOP_ExecType,  TMET_ARexx,
  369.             TMOP_Command,   xsprintf("'address DOCKSERVER; \42%s\42'", name),
  370.             TAG_DONE
  371.         };
  372.  
  373.         event->Node.ln_Name = strdup((UBYTE *)args[0]);
  374.         event->Command      = strdup((UBYTE *)args[1]);
  375.         event->Dir          = args[6]  ? strdup((UBYTE *)args[6]) : NULL;
  376.         event->Key          = args[9]  ? strdup((UBYTE *)args[9]) : NULL;
  377.         event->Output       = args[7]  ? strdup((UBYTE *)args[7]) : NULL;
  378.         event->Hotkey       = args[4];
  379.         event->Args         = args[8];
  380.         event->Activate     = args[11];
  381.         event->Type         = TMET_CLI;
  382.  
  383.         if (args[2])                                 // AREXX/S
  384.             event->Type = TMET_ARexx;
  385.  
  386.         if (args[5])                                 // WB/S
  387.             event->Type = TMET_WB;
  388.  
  389.         if (args[4])                                 // HOTKEY/S
  390.             event->Type = TMET_Hotkey;
  391.  
  392.         if (args[10])
  393.             event->Type = TMET_GoldED;               // GOLDED/S
  394.  
  395.         AddTail(&EventList, &event->Node);
  396.  
  397.         CreateTMObjectTagList(TMHandle, name, TMOBJTYPE_EXEC, execTags);
  398.     }
  399. }
  400.  
  401. /* ---------------------------------- AddIcon ----------------------------------
  402.  
  403.  Add icon object to ToolManager's pool
  404.  
  405.  template: NAME/A,FILE/A
  406.  
  407. */
  408.  
  409. void
  410. AddIcon(args, toolList)
  411.  
  412. ULONG       *args;
  413. struct List *toolList;
  414. {
  415.     struct TagItem iconTags[] = { 
  416.  
  417.         TMOP_File,  strdup((UBYTE *)args[1]),
  418.         TMOP_Data,  NULL,
  419.         TAG_DONE 
  420.     };
  421.  
  422.     CreateTMObjectTagList(TMHandle, strdup((UBYTE *)args[0]), TMOBJTYPE_IMAGE, iconTags);
  423. }
  424.  
  425.  
  426. /* --------------------------------- AddSound ----------------------------------
  427.  
  428.  Add a sound object to ToolManagers pool
  429.  
  430.  template: NAME/A,COMMAND/K/A,PORT/K/A
  431.  
  432. */
  433.  
  434. void
  435. AddSound(args, toolList)
  436.  
  437. ULONG       *args;
  438. struct List *toolList;
  439. {
  440.     struct TagItem soundTags[] = {
  441.  
  442.         TMOP_Command, strdup((UBYTE *)args[1]),
  443.         TMOP_Port,    strdup((UBYTE *)args[2]),
  444.         TAG_DONE 
  445.     };
  446.  
  447.     CreateTMObjectTagList(TMHandle, strdup((UBYTE *)args[0]), TMOBJTYPE_SOUND, soundTags);
  448. }
  449.  
  450. /* ---------------------------------- AddTool ----------------------------------
  451.  
  452.  Add a tool object (i.e. combination of command, icon, sound) to the list  of
  453.  tool  objects. This list is temporary list only; the list is appended to the
  454.  next dock created by a DOCK line found in the preset file.
  455.  
  456.  template: PROG/K/A,ICON/K,SOUND/K
  457.  
  458. */
  459.  
  460. void
  461. AddTool(args, toolList)
  462.  
  463. ULONG       *args;
  464. struct List *toolList;
  465. {
  466.     struct Tool *tool;
  467.  
  468.     if (tool = malloc(sizeof(struct Tool))) {
  469.  
  470.         tool->Exec  = args[0] ? strdup((UBYTE *)args[0]) : NULL;
  471.         tool->Icon  = args[1] ? strdup((UBYTE *)args[1]) : NULL;
  472.         tool->Sound = args[2] ? strdup((UBYTE *)args[2]) : NULL;
  473.  
  474.         AddTail(toolList, &tool->Node);
  475.     }
  476. }
  477.  
  478. /* ---------------------------------- AddDock ----------------------------------
  479.  
  480.  Add dock description to list of docks. This function won't actually create a
  481.  dock on the screen. Instead, it will create a ready-to-use tag list. Passing
  482.  this list to the ToolManager library (done by ShowDocks()) will  create  the
  483.  dock.
  484.  
  485.  template: NAME/A,X/N,Y/N,HORIZONTAL/S,COLUMNS/N,HOTKEY/K,TITLE/K,CENTER/S,POPUP/S,HIDDEN/S,TEXT/S,STICKY/S,FRONTMOST/S,PATTERN/S,VERTICAL/S,LINEAR/S
  486.  
  487. */
  488.  
  489. void
  490. AddDock(args, toolList)
  491.  
  492. ULONG       *args;
  493. struct List *toolList;
  494. {
  495.     UWORD entries;
  496.  
  497.     if (entries = CountList(toolList)) {
  498.  
  499.         struct Dock *dock;
  500.  
  501.         if (dock = malloc(sizeof(struct Dock))) {
  502.  
  503.             if (dock->Tags = (struct TagItem *)calloc((entries + 14) * sizeof(struct TagItem), 1)) {
  504.  
  505.                 struct Node *tool;
  506.                 UWORD  n;
  507.  
  508.                 dock->Tags[0].ti_Tag   = TMOP_PubScreen;
  509.  
  510.                 dock->Tags[1].ti_Tag   = TMOP_LeftEdge;
  511.                 dock->Tags[1].ti_Data  = args[1] ? *(ULONG *)args[1] : ~0;
  512.  
  513.                 dock->Tags[2].ti_Tag   = TMOP_TopEdge;
  514.                 dock->Tags[2].ti_Data  = args[2] ? *(ULONG *)args[2] : ~0;
  515.  
  516.                 dock->Tags[3].ti_Tag   = TMOP_Activated;
  517.                 dock->Tags[3].ti_Data  = !args[9];
  518.  
  519.                 dock->Tags[4].ti_Tag   = TMOP_Centered;
  520.                 dock->Tags[4].ti_Data  = args[7];
  521.  
  522.                 dock->Tags[5].ti_Tag   = TMOP_Columns;
  523.                 dock->Tags[5].ti_Data  = args[4] ? (*(ULONG *)args[4]) : (args[15] ? (args[14] ? 1 : entries) : 0);
  524.  
  525.                 dock->Tags[6].ti_Tag   = TMOP_Vertical;
  526.                 dock->Tags[6].ti_Data  = !args[14];
  527.  
  528.                 dock->Tags[7].ti_Tag   = TMOP_HotKey;
  529.                 dock->Tags[7].ti_Data  = args[5] ? strdup((UBYTE *)args[5]) : NULL;
  530.  
  531.                 dock->Tags[8].ti_Tag   = TMOP_Title;
  532.                 dock->Tags[8].ti_Data  = args[6] ? strdup((UBYTE *)args[6]) : NULL;                                        // TITLE/K
  533.  
  534.                 dock->Tags[9].ti_Tag   = TMOP_PopUp;
  535.                 dock->Tags[9].ti_Data  = args[8];                                        // TITLE/K
  536.  
  537.                 dock->Tags[10].ti_Tag  = TMOP_Text;
  538.                 dock->Tags[10].ti_Data = args[10];                                        // TITLE/K
  539.  
  540.                 dock->Tags[11].ti_Tag  = TMOP_FrontMost;
  541.                 dock->Tags[11].ti_Data = args[12];                                        // TITLE/K
  542.  
  543.                 dock->Tags[12].ti_Tag  = TMOP_Pattern;
  544.                 dock->Tags[12].ti_Data = args[13];                                        // TITLE/K
  545.  
  546.                 // to do: STICKY/S
  547.  
  548.                 for (n = 13, tool = toolList->lh_Head; tool->ln_Succ; ++n, tool = tool->ln_Succ) {
  549.  
  550.                     dock->Tags[n].ti_Tag  = TMOP_Tool;
  551.                     dock->Tags[n].ti_Data = &((struct Tool *)tool)->Exec;
  552.                 }
  553.  
  554.                 dock->Tags[n].ti_Tag  = TAG_DONE;
  555.                 dock->Tags[n].ti_Data = NULL;
  556.  
  557.                 dock->Visible  = FALSE;
  558.                 dock->Elements = entries;
  559.  
  560.                 dock->Node.ln_Name = strdup((UBYTE *)args[0]);
  561.  
  562.                 AddTail(&DockList, &dock->Node);
  563.             }
  564.         }
  565.     }
  566.     else
  567.         Puts("error: dock empty");
  568.  
  569.     NewList(toolList);
  570. }
  571.  
  572. ///
  573. /// "API management"
  574.  
  575. /* --------------------------------- HandleAPI ---------------------------------
  576.  
  577.  Register with GoldED & handle incoming API messages.
  578.  
  579. */
  580.  
  581. void
  582. HandleAPI()
  583. {
  584.     struct MsgPort *rexxPort, *apiPort;
  585.  
  586.     if (rexxPort = CreateMsgPort()) {
  587.  
  588.         if (apiPort = CreateMsgPort()) {
  589.  
  590.             struct RDArgs *rdArgs;
  591.  
  592.             if (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) {
  593.  
  594.                 UBYTE  command[255];
  595.                 ULONG *result;
  596.  
  597.                 myprintf(command, "API PORT=%ld CLASS=%ld", apiPort, API_CLASS_ROOT | API_CLASS_SCREEN | API_CLASS_REXX);
  598.  
  599.                 if ((result = SendRexxCommand(Host, command, rexxPort, FALSE, NULL, NULL)) && (*result == RC_OK)) {
  600.  
  601.                     BOOL active = TRUE;
  602.  
  603.                     do {
  604.  
  605.                         struct APIMessage *apiMsg, *nextMsg;
  606.  
  607.                         while (!(apiMsg = (struct APIMessage *)GetMsg(apiPort)))
  608.  
  609.                             WaitPort(apiPort);
  610.  
  611.                         do {
  612.  
  613.                             for (nextMsg = apiMsg; nextMsg; nextMsg = nextMsg->api_Next) {
  614.  
  615.                                 if (nextMsg->api_State == API_STATE_NOTIFY) {
  616.  
  617.                                     switch (nextMsg->api_Class) {
  618.  
  619.                                         case API_CLASS_ROOT:
  620.  
  621.                                             switch (nextMsg->api_Action) {
  622.  
  623.                                                 case API_ACTION_DIE:
  624.  
  625.                                                     active = FALSE;
  626.  
  627.                                                     HideDocks();
  628.                                                     break;
  629.  
  630.                                                 case API_ACTION_INTRODUCE:
  631.  
  632.                                                     static struct TagItem tags[] = {
  633.  
  634.                                                         API_Client_Name,      "NeXTStep",
  635.                                                         API_Client_Copyright, "©1995 Dietmar Eilert",
  636.                                                         API_Client_Purpose,   "Dock Management System",
  637.                                                         API_Client_Template,  "DOCK NAME/A,X/N,Y/N,SHOW/S,HIDE/S,TOGGLE/S,HORIZONTAL/S,VERTICAL/S,ROTATE/S,NEWLOOK/S,LINEAR/S",
  638.                                                         TAG_DONE
  639.                                                     };
  640.  
  641.                                                     nextMsg->api_Data = tags;
  642.                                                     break;
  643.  
  644.                                                 default:
  645.  
  646.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  647.                                             }
  648.  
  649.                                             break;
  650.  
  651.                                         case API_CLASS_REXX:
  652.  
  653.                                             switch (nextMsg->api_Action) {
  654.  
  655.                                                 case API_ACTION_COMMAND:
  656.  
  657.                                                     CommandDispatch(rdArgs, nextMsg);
  658.                                                     break;
  659.  
  660.                                                 default:
  661.  
  662.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  663.                                             }
  664.                                             break;
  665.  
  666.                                         case API_CLASS_SCREEN:
  667.  
  668.                                             switch (nextMsg->api_Action) {
  669.  
  670.                                                 case API_ACTION_HIDE:
  671.  
  672.                                                     HideDocks();
  673.                                                     break;
  674.  
  675.                                                 case API_ACTION_SHOW:
  676.  
  677.                                                     strcpy(Screen, nextMsg->api_Global->F_ScrnName);
  678.  
  679.                                                     ShowDocks(NULL);
  680.                                                     break;
  681.  
  682.                                                 default:
  683.  
  684.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  685.                                             }
  686.                                             break;
  687.  
  688.                                         default:
  689.  
  690.                                             nextMsg->api_Error = API_ERROR_UNKNOWN;
  691.                                     }
  692.                                 }
  693.                             }
  694.  
  695.                             ReplyMsg((struct Message *)apiMsg);
  696.  
  697.                         } while (apiMsg = (struct APIMessage *)GetMsg(apiPort));
  698.  
  699.                     } while (active);
  700.                 }
  701.  
  702.                 FreeDosObject(DOS_RDARGS, rdArgs);
  703.             }
  704.  
  705.             DeleteMsgPort(apiPort);
  706.         }
  707.  
  708.         DeleteMsgPort(rexxPort);
  709.     }
  710. }
  711.  
  712. ///
  713. /// "command dispatcher"
  714.  
  715. /* ------------------------------ CommandDispatch ------------------------------
  716.  
  717.  Dispatch commands sent by GoldED via the API interface
  718.  
  719. */
  720.  
  721. void
  722. CommandDispatch(rdArgs, apiMsg)
  723.  
  724. struct RDArgs     *rdArgs;
  725. struct APIMessage *apiMsg;
  726. {
  727.     struct APIRexxNotify *notify = (struct APIRexxNotify *)apiMsg->api_Data;
  728.  
  729.     UWORD n;
  730.  
  731.     for (n = 0; CommandParser[n].Command; ++n) {
  732.  
  733.         if (memcmp(notify->arn_Command, CommandParser[n].Command, strlen(CommandParser[n].Command)) == NULL) {
  734.  
  735.             static UBYTE buffer[1024];
  736.             
  737.             UBYTE *arguments = buffer + strlen(CommandParser[n].Command);
  738.  
  739.             strcpy(buffer, notify->arn_Command);
  740.             strcat(buffer, "\12");
  741.  
  742.             rdArgs->RDA_Source.CS_Buffer = arguments;
  743.             rdArgs->RDA_Source.CS_Length = strlen(arguments);
  744.             rdArgs->RDA_Source.CS_CurChr = 0;
  745.             rdArgs->RDA_DAList           = NULL;
  746.             rdArgs->RDA_Buffer           = NULL;
  747.  
  748.             if (CommandParser[n].Template) {
  749.  
  750.                 ULONG argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  751.  
  752.                 if (ReadArgs(CommandParser[n].Template, argArray, rdArgs)) {
  753.  
  754.                     notify->arn_RC = (*(LONG (*)(ULONG *, struct APIMessage *))CommandParser[n].Server)(argArray, apiMsg);
  755.  
  756.                     FreeArgs(rdArgs);
  757.                 }
  758.                 else {
  759.  
  760.                     static char errorText[81];
  761.  
  762.                     Fault(IoErr(), "IoErr()", errorText, 80);
  763.  
  764.                     notify->arn_RC           = RC_WARN;
  765.                     notify->arn_CommandError = errorText;
  766.                 }
  767.             }
  768.             else
  769.                 notify->arn_RC = (*(LONG (*)(ULONG *, struct APIMessage *))CommandParser[n].Server)(NULL, apiMsg);
  770.  
  771.             apiMsg->api_State = API_STATE_CONSUMED;
  772.         }
  773.     }
  774. }
  775.  
  776. /* -------------------------------- ModifyDock ---------------------------------
  777.  
  778.  Modify look of a dock
  779.  
  780.  template: NAME/A,X/N,Y/N,SHOW/S,HIDE/S,TOGGLE/S,HORIZONTAL/S,VERTICAL/S,ROTATE/S,NEWLOOK/S,LINEAR/S
  781.  
  782. */
  783.  
  784. LONG
  785. ModifyDock(args, apiMsg)
  786.  
  787. ULONG  *args;
  788. struct APIMessage *apiMsg;
  789. {
  790.     struct Dock *dock;
  791.  
  792.     if (dock = SearchName(&DockList, (UBYTE *)args[0])) {
  793.  
  794.         struct TagItem *tag;
  795.         BOOL            visible;
  796.  
  797.         if (visible = dock->Visible)
  798.             DeleteTMObject(TMHandle, dock->Node.ln_Name);
  799.  
  800.         dock->Visible = FALSE;
  801.  
  802.         if (args[1])                                 // X/N
  803.  
  804.             FindTagItem(TMOP_LeftEdge, dock->Tags)->ti_Data = *(ULONG *)args[1];
  805.  
  806.         if (args[2])                                 // Y/N
  807.  
  808.             FindTagItem(TMOP_TopEdge, dock->Tags)->ti_Data = *(ULONG *)args[2];
  809.  
  810.         tag = FindTagItem(TMOP_Vertical, dock->Tags);
  811.  
  812.         if (args[6])                                 // HORIZONTAL/S
  813.             tag->ti_Data = TRUE;
  814.  
  815.         if (args[7])                                 // VERTICAL/S
  816.             tag->ti_Data = FALSE;
  817.  
  818.         if (args[8])                                 // ROTATE/S
  819.             tag->ti_Data = !tag->ti_Data;
  820.  
  821.         if (args[10])                                // LINEAR/S
  822.  
  823.             FindTagItem(TMOP_Columns, dock->Tags)->ti_Data = (tag->ti_Data) ? dock->Elements : 1;
  824.  
  825.         tag = FindTagItem(TMOP_Text, dock->Tags);
  826.  
  827.         if (args[9])                                 // NEWLOOK/S
  828.             tag->ti_Data = !tag->ti_Data;
  829.  
  830.         if (args[3])                                 // SHOW/S
  831.             visible = TRUE;
  832.  
  833.         if (args[4])                                 // HIDE/S
  834.             visible = FALSE;
  835.  
  836.         if (args[5])                                 // TOGGLE/S
  837.             visible = !visible;
  838.  
  839.         if (visible)
  840.             ShowDocks(dock);
  841.     }
  842.     else
  843.         Puts("Unknow dock");
  844.  
  845.     return(RC_OK);
  846. }
  847.  
  848. ///
  849. /// "dock handling"
  850.  
  851. /* --------------------------------- ShowDocks ---------------------------------
  852.  
  853.  Show specified (hidden) dock or all hidden docks if <dock> is FALSE.
  854.  
  855. */
  856.  
  857. void
  858. ShowDocks(showDock)
  859.  
  860. struct Dock *showDock;
  861. {
  862.     struct Screen *scr;
  863.  
  864.     if (scr = LockPubScreen(Screen)) {
  865.  
  866.         struct Dock *dock;
  867.  
  868.         for (dock = (struct Dock *)DockList.lh_Head; dock->Node.ln_Succ; dock = (struct Dock *)dock->Node.ln_Succ) {
  869.  
  870.             if (!dock->Visible) {
  871.  
  872.                 if ((dock == showDock) || (showDock == NULL)) {
  873.  
  874.                     struct TagItem *tag;
  875.  
  876.                     FindTagItem(TMOP_PubScreen, dock->Tags)->ti_Data = Screen;
  877.  
  878.                     if ((tag = FindTagItem(TMOP_LeftEdge, dock->Tags))->ti_Data == ~0)
  879.                         tag->ti_Data = scr->Width;
  880.  
  881.                     if ((tag = FindTagItem(TMOP_TopEdge, dock->Tags))->ti_Data == ~0)
  882.                         tag->ti_Data = scr->BarHeight + ((scr->BitMap.Depth == 1) ? 2 : 1);
  883.  
  884.                     if (CreateTMObjectTagList(TMHandle, dock->Node.ln_Name, TMOBJTYPE_DOCK, dock->Tags))
  885.                         dock->Visible = TRUE;
  886.                     else
  887.                         Puts("Couldn't create dock object");
  888.                 }
  889.             }
  890.         }
  891.  
  892.         UnlockPubScreen(NULL, scr);
  893.     }
  894. }
  895.  
  896. /* --------------------------------- HideDocks ---------------------------------
  897.  
  898.  Hide all open docks
  899.  
  900. */
  901.  
  902. void
  903. HideDocks()
  904. {
  905.     struct Dock *dock;
  906.  
  907.     for (dock = (struct Dock *)DockList.lh_Head; dock->Node.ln_Succ; dock = (struct Dock *)dock->Node.ln_Succ) {
  908.  
  909.         if (dock->Visible) {
  910.  
  911.             DeleteTMObject(TMHandle, dock->Node.ln_Name);
  912.  
  913.             dock->Visible = FALSE;
  914.         }
  915.     }
  916. }
  917.  
  918.  
  919. ///
  920. /// "misc"
  921.  
  922. /* -------------------------------- PutIEvents ---------------------------------
  923.  
  924.  Add keyboard events to global stream of input events. Works  recursively  to
  925.  invert   the  given  linked  list  of  events  (which  is  inverted  due  to
  926.  InvertString). Restores the links after usage  to  support  a  FreeIEvents()
  927.  call later on.
  928.  
  929. */
  930.  
  931. void
  932. PutIEvents(inputEvent)
  933.  
  934. struct InputEvent *inputEvent;
  935. {
  936.     struct InputEvent *next;
  937.  
  938.     if (next = inputEvent->ie_NextEvent)
  939.         PutIEvents(next);
  940.  
  941.     inputEvent->ie_NextEvent = NULL;
  942.  
  943.     AddIEvents(inputEvent);
  944.  
  945.     inputEvent->ie_NextEvent = next;
  946. }
  947.  
  948. /* ---------------------------------- InsertEvent ------------------------------
  949.  
  950.  Insert string into input event loop. String is interpreted. Return FALSE on
  951.  failure (interpretation error).
  952.  
  953. */
  954.  
  955. void
  956. InsertEvent(string)
  957.  
  958. UBYTE *string;
  959. {
  960.     struct InputEvent *inputEvent;
  961.  
  962.     if (inputEvent = MyInvertString(string, NULL)) {
  963.  
  964.         PutIEvents   (inputEvent);
  965.         MyFreeIEvents(inputEvent);
  966.     }
  967. }
  968.  
  969.  
  970. /* ---------------------------------- stristr ----------------------------------
  971.  
  972.  strstr replacement: case insensitive (recursive)
  973.  
  974. */
  975.  
  976. UBYTE *
  977. stristr(buffer, pattern)
  978.  
  979. UBYTE *buffer, *pattern;
  980. {
  981.     if (*pattern) {
  982.  
  983.         while (*buffer) {
  984.  
  985.             if (toupper(*buffer) == *pattern)
  986.                 if (stristr(buffer + 1, pattern + 1))
  987.                     return(buffer);
  988.  
  989.             ++buffer;
  990.         }
  991.  
  992.         return(NULL);
  993.     }
  994.     else
  995.         return(buffer);
  996. }
  997.  
  998. /* ---------------------------------- Replace ----------------------------------
  999.  
  1000.  Replace given <pattern> within <buffer> by <new> (case insensitive)
  1001.  
  1002. */
  1003.  
  1004. void
  1005. Replace(buffer, pattern, new)
  1006.  
  1007. UBYTE *buffer, *pattern, *new;
  1008. {
  1009.     UWORD newLen;
  1010.     
  1011.     for (newLen = strlen(new); buffer = stristr(buffer, pattern); buffer += newLen) {
  1012.  
  1013.         WORD diffLen = newLen - strlen(pattern);
  1014.  
  1015.         if (diffLen > 0)
  1016.             movmem(buffer, buffer + diffLen, strlen(buffer) + 1);
  1017.  
  1018.         if (diffLen < 0)
  1019.             strcpy(buffer, buffer - diffLen);
  1020.  
  1021.         movmem(new, buffer, newLen);
  1022.     }
  1023. }
  1024.  
  1025.  
  1026. /* -------------------------------- SearchName ---------------------------------
  1027.  
  1028.  Search for named node; case insensitive FindName() replacement
  1029.  
  1030. */
  1031.  
  1032. struct Node *
  1033. SearchName(list, name)
  1034.  
  1035. struct List *list;
  1036. UBYTE       *name;
  1037. {
  1038.     struct Node *node;
  1039.  
  1040.     if (node = FindName(list, name))
  1041.         return(node);
  1042.  
  1043.     for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
  1044.         if (node->ln_Name && (stricmp(name, node->ln_Name) == 0))
  1045.             return(node);
  1046.  
  1047.     return(NULL);
  1048. }
  1049.  
  1050. /* ----------------------------------- Puts ------------------------------------
  1051.  
  1052.  puts() replacement; saves another 2K ;-)
  1053.  
  1054. */
  1055.  
  1056. void
  1057. Puts(text)
  1058.  
  1059. UBYTE *text;
  1060. {
  1061.     Write(Output(), text, strlen(text));
  1062.     Write(Output(), "\n", 1);
  1063. }
  1064.  
  1065.  
  1066. /* ---------------------------------- CountList --------------------------------
  1067.  
  1068.  Count nodes of a list
  1069.  
  1070. */
  1071.  
  1072. UWORD
  1073. CountList(list)
  1074.  
  1075. struct List *list;
  1076. {
  1077.     UWORD  count;
  1078.     struct Node *nextNode;
  1079.  
  1080.     for (count = 0, nextNode = list->lh_Head; nextNode->ln_Succ; nextNode = nextNode->ln_Succ)
  1081.         count++;
  1082.  
  1083.     return(count);
  1084. }
  1085.  
  1086.  
  1087. /* --------------------------------- xsprintf ----------------------------------
  1088.  
  1089.  sprintf frontend (malloc buffer); limited to string insertion into string
  1090.  
  1091. */
  1092.  
  1093. UBYTE *
  1094. xsprintf(mask, var)
  1095.  
  1096. UBYTE *mask, *var;
  1097. {
  1098.     char *buffer;
  1099.  
  1100.     if (buffer = malloc(strlen(mask) + strlen(var)))
  1101.         myprintf(buffer, mask, var);
  1102.  
  1103.     return(buffer);
  1104. }
  1105.  
  1106. ///
  1107. /// "ARexx"
  1108.  
  1109. /* ---------------------------------- SendRexxCommand -------------------------
  1110.  
  1111.  Send ARexx message & wait for answer. Don't wait for reply  in  asynchronous
  1112.  mode.  In  synchronous mode: return pointer to result or NULL. Result string
  1113.  is written to <buffer> if <buffer> is valid. In  asynchronous  mode:  return
  1114.  TRUE (message sent; increase <counter>) or NULL.
  1115.  
  1116. */
  1117.  
  1118. ULONG *
  1119. SendRexxCommand(port, cmd, replyPort, async, counter, buffer)
  1120.  
  1121. UBYTE *cmd, *port, *buffer;
  1122. UWORD *counter;
  1123. BOOL   async;
  1124. struct MsgPort *replyPort;
  1125. {
  1126.     struct MsgPort *rexxport;
  1127.  
  1128.     Forbid();
  1129.  
  1130.     if (rexxport = FindPort(port)) {
  1131.  
  1132.         struct RexxMsg *rexxMsg;
  1133.  
  1134.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  1135.  
  1136.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  1137.  
  1138.                 static ULONG result;
  1139.  
  1140.                 struct RexxMsg *answer;
  1141.  
  1142.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  1143.  
  1144.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  1145.  
  1146.                 Permit();
  1147.  
  1148.                 if (counter)
  1149.                     ++*counter;
  1150.  
  1151.                 if (async)
  1152.                     return(TRUE);
  1153.  
  1154.                 do {
  1155.  
  1156.                     WaitPort(replyPort);
  1157.  
  1158.                     if (answer = (struct RexxMsg *)GetMsg(replyPort)) {
  1159.  
  1160.                         if (answer->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  1161.  
  1162.                             if (counter)
  1163.                                 --*counter;
  1164.  
  1165.                             if (answer == rexxMsg) {
  1166.  
  1167.                                 if ((result = answer->rm_Result1) == RC_OK) {
  1168.  
  1169.                                     if (answer->rm_Result2 && buffer)
  1170.                                         strcpy(buffer, (char *)answer->rm_Result2);
  1171.                                 }
  1172.                             }
  1173.  
  1174.                             FreeRexxCommand(answer);
  1175.                         }
  1176.                         else {
  1177.  
  1178.                             answer->rm_Result1 = RC_FATAL;
  1179.  
  1180.                             ReplyMsg((struct Message *)answer);
  1181.                         }
  1182.                     }
  1183.  
  1184.                 } while (answer != rexxMsg);
  1185.  
  1186.                 return(&result);
  1187.             }
  1188.         }
  1189.     }
  1190.  
  1191.     Permit();
  1192.  
  1193.     return(NULL);
  1194. }
  1195.  
  1196. /* ------------------------------- CloseRexxPort -------------------------------
  1197.  
  1198.  Close an ARexx  port.  Wait  until  all  outstanding  (i.e.  sent)  messages
  1199.  (<missing>)  have  been  replied.  Remove  port from list of public ports if
  1200.  <removePort> is TRUE.
  1201.  
  1202. */
  1203.  
  1204. void
  1205. CloseRexxPort(port, missing, removePort)
  1206.  
  1207. struct MsgPort *port;
  1208. UWORD  missing;
  1209. BOOL   removePort;
  1210. {
  1211.     if (removePort)
  1212.         RemPort(port);
  1213.  
  1214.     Forbid();
  1215.  
  1216.     while (missing) {
  1217.  
  1218.         struct RexxMsg *rexxMsg;
  1219.  
  1220.         Wait(1L<<port->mp_SigBit);
  1221.  
  1222.         while (rexxMsg = (struct RexxMsg *)GetMsg(port)) {
  1223.  
  1224.             if (rexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  1225.  
  1226.                 FreeRexxCommand(rexxMsg);
  1227.  
  1228.                 missing--;
  1229.             }
  1230.             else {
  1231.  
  1232.                 rexxMsg->rm_Result1 = RC_FATAL;
  1233.  
  1234.                 ReplyMsg((struct Message *)rexxMsg);
  1235.             }
  1236.         }
  1237.     }
  1238.  
  1239.     DeleteMsgPort(port);
  1240.  
  1241.     Permit();
  1242. }
  1243.  
  1244. /* ------------------------------- FreeRexxCommand ----------------------------
  1245.  
  1246.  Free memory/file handles related to message <rexxmessage> replied by the
  1247.  ARexx server.
  1248.  
  1249. */
  1250.  
  1251. void
  1252. FreeRexxCommand(rexxMsg)
  1253.  
  1254. struct RexxMsg *rexxMsg;
  1255. {
  1256.     if (rexxMsg->rm_Result1 == RC_OK) 
  1257.         if (rexxMsg->rm_Result2)
  1258.             DeleteArgstring((char *)rexxMsg->rm_Result2);
  1259.  
  1260.     if (rexxMsg->rm_Stdin)
  1261.         Close(rexxMsg->rm_Stdin);
  1262.  
  1263.     if (rexxMsg->rm_Stdout && (rexxMsg->rm_Stdout != rexxMsg->rm_Stdin))
  1264.         Close(rexxMsg->rm_Stdout);
  1265.  
  1266.     DeleteArgstring((char *)ARG0(rexxMsg));
  1267.  
  1268.     DeleteRexxMsg(rexxMsg);
  1269. }
  1270.  
  1271. ///
  1272. /// "execute programs"
  1273.  
  1274. /* -------------------------------- DoExecute ------------------------------------
  1275.  
  1276.  Execute a DOS command.
  1277.  
  1278. */
  1279.  
  1280. void
  1281. DoExecute(cmd, async, output, directory, stack, prio)
  1282.  
  1283. UBYTE *cmd, *output, *directory;
  1284. UWORD stack;
  1285. WORD  prio;
  1286. BOOL  async;
  1287. {
  1288.     BPTR newCurrentDir;
  1289.  
  1290.     if (!directory)
  1291.         directory = "progdir:";
  1292.  
  1293.     if (!output)
  1294.         output = "NIL:";
  1295.  
  1296.     if (newCurrentDir = Lock(directory, SHARED_LOCK)) {
  1297.  
  1298.         BPTR inHandle, outHandle, oldCurrentDir = CurrentDir(newCurrentDir);
  1299.  
  1300.         if (outHandle = Open(output, MODE_NEWFILE)) {
  1301.  
  1302.             struct TagItem tagItems[] = {
  1303.  
  1304.                 SYS_Output,      NULL,
  1305.                 SYS_Input ,      NULL,
  1306.                 NP_ConsoleTask,  NULL,
  1307.                 SYS_UserShell,   TRUE,
  1308.                 SYS_Asynch,      async,
  1309.                 NP_StackSize,    stack,
  1310.                 NP_Priority,     prio,
  1311.                 TAG_DONE 
  1312.             };
  1313.  
  1314.             struct MsgPort *oldct, *newct;
  1315.  
  1316.             BOOL success = FALSE;
  1317.  
  1318.             if (IsInteractive(outHandle)) {
  1319.  
  1320.                 newct = ((struct FileHandle *)BADDR(outHandle))->fh_Type;
  1321.                 oldct = SetConsoleTask(newct);
  1322.  
  1323.                 inHandle = Open("CONSOLE:", MODE_OLDFILE);
  1324.  
  1325.                 SetConsoleTask(oldct);
  1326.             }
  1327.             else {
  1328.  
  1329.                 inHandle = Open("NIL:", MODE_OLDFILE);
  1330.                 newct    = NULL;
  1331.             }
  1332.  
  1333.             if (inHandle) {
  1334.  
  1335.                 tagItems[0].ti_Data = outHandle;
  1336.                 tagItems[1].ti_Data = inHandle;
  1337.                 tagItems[2].ti_Data = newct;
  1338.  
  1339.                 if (SystemTagList(cmd, tagItems) != -1L)
  1340.                     success = TRUE;
  1341.  
  1342.                 if (!(async && success))
  1343.                     Close(inHandle);
  1344.             }
  1345.  
  1346.             if (!(async && success))
  1347.                 Close(outHandle);
  1348.         }
  1349.  
  1350.         CurrentDir(oldCurrentDir);
  1351.  
  1352.         UnLock(newCurrentDir);
  1353.     }
  1354. }
  1355.  
  1356. ///
  1357. /// "Server"
  1358.  
  1359. /* -------------------------------- ARexxServer --------------------------------
  1360.  
  1361.  ARexx server; used to process  ARexx  commands  sent  by  ToolManager.  This
  1362.  function  is  installed  as  background  task.  Run until a SIG_HANDSHAKE is
  1363.  recieved from the  main  task.  Rise  SIG_HANDSHAKE  on  exit  (multitasking
  1364.  disabled,  i.e.  if  the  main  task  detects  the signal, this task is gone
  1365.  already).
  1366.  
  1367. */
  1368.  
  1369. __geta4 void
  1370. ARexxServer()
  1371. {
  1372.     struct MsgPort *port;
  1373.  
  1374.     Forbid();
  1375.  
  1376.     if (port = CreateMsgPort()) {
  1377.  
  1378.         ULONG mask;
  1379.         UWORD missing = 0;
  1380.  
  1381.         port->mp_Node.ln_Name = "DOCKSERVER";
  1382.  
  1383.         AddPort(port);
  1384.  
  1385.         do {
  1386.  
  1387.             struct RexxMsg *rexxMsg;
  1388.  
  1389.             mask = Wait(1L<<(port->mp_SigBit) | SIG_KILL);
  1390.  
  1391.             while (rexxMsg = (struct RexxMsg *)GetMsg(port)) {
  1392.  
  1393.                 if (rexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  1394.  
  1395.                     FreeRexxCommand(rexxMsg);
  1396.  
  1397.                     if (missing)
  1398.                         missing--;
  1399.                 }
  1400.                 else {
  1401.  
  1402.                     struct Event *event;
  1403.  
  1404.                     if (event = (struct Event *)SearchName(&EventList, ARG0(rexxMsg))) {
  1405.  
  1406.                         if (event->Command) {
  1407.  
  1408.                             static UBYTE buffer[1024];
  1409.  
  1410.                             strcpy(buffer, event->Command);
  1411.  
  1412.                             Replace(buffer, "%SCREEN", Screen);
  1413.                             Replace(buffer, "%GOLDED", Host  );
  1414.  
  1415.                             if (event->Activate)
  1416.                                 SendRexxCommand(Host, "WINDOW FORCE", port, TRUE, &missing, NULL);
  1417.  
  1418.                             switch (event->Type) {
  1419.  
  1420.                                 case TMET_ARexx:
  1421.  
  1422.                                     SendRexxCommand("AREXX", buffer, port, TRUE, &missing, NULL);
  1423.                                     break;
  1424.  
  1425.                                 case TMET_GoldED:
  1426.  
  1427.                                     SendRexxCommand(Host, buffer, port, TRUE, &missing, NULL);
  1428.                                     break;
  1429.  
  1430.                                 case TMET_CLI:
  1431.                                 case TMET_WB:
  1432.  
  1433.                                     DoExecute(buffer, TRUE, event->Output, event->Dir, 8192, 0);
  1434.                                     break;
  1435.  
  1436.                                 case TMET_Hotkey:
  1437.  
  1438.                                     InsertEvent(buffer);
  1439.                                     break;
  1440.                             }
  1441.                         }
  1442.                     }
  1443.  
  1444.                     rexxMsg->rm_Result1 = NULL;
  1445.                     rexxMsg->rm_Result2 = NULL;
  1446.  
  1447.                     ReplyMsg((struct Message *)rexxMsg);
  1448.                 }
  1449.             }
  1450.  
  1451.         } while (!(mask & SIG_KILL));
  1452.  
  1453.         CloseRexxPort(port, missing, TRUE);
  1454.     }
  1455.     else
  1456.         Wait(SIG_KILL);
  1457.  
  1458.     Forbid();
  1459.  
  1460.     Signal(MainTask, SIG_HANDSHAKE);
  1461. }
  1462.  
  1463. ///
  1464.